package com.whynot.frame.springMvc.servlet;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.whynot.frame.springMvc.annotation.Controller;
import com.whynot.frame.springMvc.annotation.RequestMapping;
import com.whynot.frame.springMvc.annotation.Resource;
import com.whynot.frame.springMvc.annotation.Service;

public class DispatcherServlet extends HttpServlet{
	
	List<String> packageList = new ArrayList<String>();
	
	Map<String,Object> beans = new HashMap<String,Object>();
	
	Map<String,Method> handlerMappings = new HashMap<String,Method>();
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doPost(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
		String uri = req.getRequestURI();
		String context = req.getContextPath();
		
		String path = uri.replace(context, "");
		
		Object obj = beans.get("/"+path.split("/")[1]);
		
		Method method = handlerMappings.get(path);
		
		try {
			method.invoke(obj, new Object[] {req,resp});
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public void init() throws ServletException {
		//1。扫描对应包下的类
		scanPackage("com.chenyao.springmvc");
		//2。创建实例
		try {
			instance();
		} catch (Exception e) {
			e.printStackTrace();
		}
		//3。Ioc注入依赖关系
		iocInject();
		//4。Url与rest建立映射关系
		handlerMapping();
		// TODO Auto-generated method stub
		super.init();
	}
	
	private void handlerMapping() {
		// TODO Auto-generated method stub
		if(packageList.size() <= 0){
			return;
		}
		for(Map.Entry<String, Object> map : beans.entrySet()){
			Class<?> clazz = map.getValue().getClass();
			if(clazz.isAnnotationPresent(Controller.class)){
				RequestMapping rm = (RequestMapping) clazz.getAnnotation(RequestMapping.class);
				String restKey = rm.value();
				Method[] methods = clazz.getDeclaredMethods();
				for(Method method : methods){
					if(method.isAnnotationPresent(RequestMapping.class)){
						RequestMapping methodRm =method.getAnnotation(RequestMapping.class);
						String methodValue = methodRm.value();
						handlerMappings.put(restKey+methodValue, method);
					}
				}
			}
		}
	}

	private void iocInject() {
		// TODO Auto-generated method stub
		if(packageList.size() <= 0){
			return;
		}
		for(Map.Entry<String, Object> map : beans.entrySet()){
			Field[] fields = map.getValue().getClass().getDeclaredFields();
			for(Field field : fields){
				field.setAccessible(true);
				if(field.isAnnotationPresent(Resource.class)){
					Resource resource = field.getAnnotation(Resource.class);
					String value = resource.name();
					try {
						field.set(map.getValue(), beans.get(value));
					} catch (IllegalArgumentException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (IllegalAccessException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}
	}

	private void instance() throws Exception {
		// TODO Auto-generated method stub
		if(packageList.size() <= 0){
			return;
		}
		
		for(String className : packageList){
			Class<?> clazz = Class.forName(className.replace(".class", ""));
			if(clazz.isAnnotationPresent(Controller.class)){
				Object obj = clazz.newInstance();
				RequestMapping rm = (RequestMapping) clazz.getAnnotation(RequestMapping.class);
				String restKey = rm.value();
				beans.put(restKey, obj);
			}
			if(clazz.isAnnotationPresent(Service.class)){
				Object obj = clazz.newInstance();
				Service rm = (Service) clazz.getAnnotation(Service.class);
				String beanKey = rm.value();
				beans.put(beanKey, obj);
			}
			
		}
		
	}

	private void scanPackage(String scanPackage){
		URL url = this.getClass().getClassLoader().getResource("/"+replaceTo(scanPackage));
		String filePath = url.getFile();
		
		File file = new File(filePath);
		String[] filePaths = file.list();
		
		for(String curPath : filePaths){
			File curFile = new File(filePath+curPath);
			if(curFile.isDirectory()){
				scanPackage(scanPackage+"."+curFile.getName());
			}else{
				packageList.add(scanPackage+"."+curFile.getName());
			}
		}
	}
	
	private String replaceTo(String scanPackage){
		return scanPackage.replaceAll("\\.", "/");
	}

}
